#ifndef __IMPROVE_DIV_H
#define __IMPROVE_DIV_H
#include "../modularity_mat/modularity_mat.h"
#include "../sparse_mlpl/sparse_matrix.h"
#include "../spectral_div/spectral_div.h"


 /*executes algorithm 4 in high level*/
int ImproveDivision(int *GroupVertexDegrees,int M, sparse_matrix_lst* A_g,elem** B_g,elem* vector_S,elem* pDeltaQ, int* Group,int iOriginalGroupLength, int* FirstSubGroup,int iSubGroupLength,int *numOfIter);
 /*reads file, allocates and fills the given array with the group indices. updates also the group size pointer*/
int FileToArray(char* sFileName, int* iGroupLength, int** Group_ptr);
 /*validates that the second input group is indeed a sub-group of the original one, and computes the division vector (S) */
int IsSubsetGroup(int* Group, int iGroupLength, int* SubGroup, int iSubGroupLength,elem** DivisionVector);
/*multiplies B_g by a given vector*/
int Mult_ModMat_Vector(sparse_matrix_lst* A_g,int* GroupVertexDegrees,int M,int iGroupSize,elem* Vector,elem* ResultVec);
 /*multiplies 2 vectors */
elem DotProduct(int* VectorA, elem* VectorB, int iLength);
 /*add a vector to given vector, coordinate by coordinate */
void AddVectorToVector(elem* ResultVector, elem* AddedVector, int iVecLength);
 /*find index of maximal value*/
int ImproveArgmax(elem *Improve,int iVectorLength);
 /*find an UNMOVED index of maximal value*/
int UnmovedArgmax(elem *Score,int iVectorLength,int* Unmoved);
 /*initialize the score vector */
int InitialScore(sparse_matrix_lst* A_g,int* GroupVertexDegrees,int M, elem* vector_S, elem* Score,int iGroupSize);
 /*update the score vector  */
int UpdateScore(elem* Score,elem** B_g,elem* s,int k,int iGroupSize);
 /*trying to find an improvement of the partition defined by s (lines 3-20 in alg 4)*/
int FindImprovement(elem** B_g,sparse_matrix_lst* A_g,int iGroupSize,int* GroupVertexDegrees,int M,elem* vector_S,elem* Score,int* Unmoved,elem* Improve,int* Indices);
 /*Find the maximum improvement of s and update s accordingly */
int FindMaxImprovement(elem* vector_s,int iGroupSize,elem* Score,elem* Improve,int* Indices,elem* pDeltaQ);
 /* compute and return the new improved groups & their sizes, and also deltaQ*/
int CalculateNewDivisionGroups(sparse_matrix_lst* A, elem** B_g, int* GroupVertexDegrees, int M, int iGroupSize, int* OriginalGroup, int *OriginalSubGroup, elem* vector_S,
					 int iOriginalSubGroupSize,int **ImprovedGroup1_ptr, int* pFirstImpGroupSize, int **ImprovedGroup2_ptr, int* pSecondImpGroupSize, elem* pDeltaQ,int *numOfIter);
 /*exit safely overloaded functions (to be called upon mem allocation failure or when program needs to exit)*/
void ExitSafely1(int *GroupVertexDegrees,int *Unmoved, int *Indices,elem *Score, elem *Improve);
void ExitSafely2(elem* Arr);
void ExitSafely3(int* Arr, FILE* fp);
void ExitSafely4(sparse_matrix_lst* A_g,elem* F_g,elem **GnrModMat,int iGroupSize);
void ExitSafely5(sparse_matrix_lst* A,elem** B_g,elem* vector_S,int *NewGroup1, int*NewGroup2, int iGroupSize,int *OriginalGroup,int *OriginalSubGroup,int *GroupVertexDegrees);

#endif /*__IMPROVE_DIV_H*/